#ifndef IVGI
#define IVGI

struct IVGI_DATA
{
    float3 L0;
};

float _IVGIIndexGrid[1000];
float3 _IVGIDataBuffer_L0[1000];
float3 _IVGIDataBuffer_Luminance[1000];
float3 _GridOrigin;
float _VoxelSize;
int _GridDim;

// float3 SampleIVGI(float3 positionWS, float3 normalWS, float dataIndex)
// {
//     float3 localPos = (positionWS - _GridOrigin) / _VoxelSize;
//     int3 voxelCoord = floor(localPos);// int3(floor(localPos));
//     voxelCoord = clamp(voxelCoord, int3(0, 0, 0), int3(_GridDim, _GridDim, _GridDim) - 1);
//     int index = _IVGIIndexGrid[voxelCoord.x * _GridDim * _GridDim + voxelCoord.y * _GridDim + voxelCoord.z];
//     
//     Light light = GetMainLight();
//     // float ndl = dot(light.direction, normalize(normalWS));
//     float ndl = dot(_IVGIDataBuffer_Luminance[index], normalize(normalWS));
//     // ndl = saturate(ndl);
//     // ndl = smoothstep(0.0, 1.0, ndl);
//     //float3 finalColor = _IVGIDataBuffer_L0[index] + _IVGIDataBuffer_L0[index] * _IVGIDataBuffer_Luminance[index];
//     // float3 finalColor = _IVGIDataBuffer_L0[dataIndex] + _IVGIDataBuffer_L0[dataIndex] * ndl;
//     return float3(_IVGIDataBuffer_L0[dataIndex]);
// }

struct FTwoBandSHVectorFloat
{
    float4 Value;
};

struct FTwoBandSHVectorRGBFloat
{
    FTwoBandSHVectorFloat R;
    FTwoBandSHVectorFloat G;
    FTwoBandSHVectorFloat B;
};

/* 二阶三通道球谐解压
 * 
 * Step 1 解压数值
 */
void UnpackBouncedSkyVis_L0L1RGB_ToEncodedLum(float3 PackedL0RGB, float3 PackedL1Lum, out float3 L0RGB,
                                              out float3 L1Lum)
{
    L0RGB.xyz = PackedL0RGB.xyz * 2.0f * PI;
    L1Lum.xyz = (PackedL1Lum.xyz - 0.5f) * 2.0f * 10.0f;
}

/* Step 2 把L1Lum解压为L1RGB
 */
void DecodeLumBouncedSkyVis_L0L1RGB(float3 L0RGB, float3 L1Lum, out FTwoBandSHVectorRGBFloat SH)
{
    float L0Lum = Max3(L0RGB.r, L0RGB.g, L0RGB.b);
    float L1YLum = L1Lum[1];
    float L1ZLum = L1Lum[2];
    float L1XLum = L1Lum[0];

    float3 L1R = float3(L1XLum * L0RGB.r / L0Lum, L1YLum * L0RGB.r / L0Lum, L1ZLum * L0RGB.r / L0Lum);
    // L0RGB.x / L0Lum 为R通道占Lum比例
    float3 L1G = float3(L1XLum * L0RGB.g / L0Lum, L1YLum * L0RGB.g / L0Lum, L1ZLum * L0RGB.g / L0Lum);
    // L0RGB.y / L0Lum 为G通道占Lum比例
    float3 L1B = float3(L1XLum * L0RGB.b / L0Lum, L1YLum * L0RGB.b / L0Lum, L1ZLum * L0RGB.b / L0Lum);
    // L0RGB.z / L0Lum 为B通道占Lum比例

    SH.R.Value = float4(L0RGB.r, L1R);
    SH.G.Value = float4(L0RGB.g, L1G);
    SH.B.Value = float4(L0RGB.b, L1B);
}

float4 EvalSHTwoBand(float3 InputVector)
{
    float4 Result;
    Result.x = 0.2820947917f;
    Result.y = -0.4886025119f * InputVector.y;
    Result.z = 0.4886025119f * InputVector.z;
    Result.w = -0.4886025119f * InputVector.x;
    return Result;
}


/* 二阶三通道球谐计算
 */
float3 SHEvaluate_L0L1RGB(float3 Normal, FTwoBandSHVectorRGBFloat L0L1RGB)
{
    const float4 SHValue_L0L1R = EvalSHTwoBand(Normal);
    float3 Result;
    Result.r = dot(SHValue_L0L1R, L0L1RGB.R.Value);
    Result.g = dot(SHValue_L0L1R, L0L1RGB.G.Value);
    Result.b = dot(SHValue_L0L1R, L0L1RGB.B.Value);
    return Result;
}

float3 SampleIVGI_0(float3 positionWS, float3 normalWS, int dataIndex)
{
    float3 localPos = (positionWS - _GridOrigin) / _VoxelSize;
    float3 voxelF = clamp(localPos, 0.0, _GridDim - 1.001); // 防止越界
    int3 baseCoord = (int3)floor(voxelF);
    float3 voxelFrac = frac(voxelF);

    // 准备插值结果
    float3 L0 = 0;
    float3 L1dir = 0;
    Light light = GetMainLight();
    // 遍历 8 个邻居 probe 点
    for (int x = 0; x <= 1; ++x)
        for (int y = 0; y <= 1; ++y)
            for (int z = 0; z <= 1; ++z)
            {
                int3 offset = int3(x, y, z);
                int3 probeCoord = baseCoord + offset;
                probeCoord = clamp(probeCoord, int3(0, 0, 0), int3(_GridDim, _GridDim, _GridDim) - 1);

                int index = _IVGIIndexGrid[probeCoord.x * _GridDim * _GridDim + probeCoord.y * _GridDim + probeCoord.z];

                float weight =
                    (x == 0 ? (1.0 - voxelFrac.x) : voxelFrac.x) *
                    (y == 0 ? (1.0 - voxelFrac.y) : voxelFrac.y) *
                    (z == 0 ? (1.0 - voxelFrac.z) : voxelFrac.z);

                L0 += _IVGIDataBuffer_L0[index] * weight;
                L1dir += _IVGIDataBuffer_Luminance[index] * weight;
            }

    float ndl = saturate(dot(normalize(normalWS), normalize(L1dir)));
    return L0 + L0 * ndl; // L0 + L1（灰度方向）
}

float3 SampleIVGI_1(float3 positionWS, float3 normalWS, int dataIndex)
{
    float3 localPos = (positionWS - _GridOrigin) / _VoxelSize;
    float3 voxelF = clamp(localPos, 0.0, _GridDim - 1.001); // 防止越界
    int3 baseCoord = (int3)floor(voxelF);
    float3 voxelFrac = frac(voxelF);

    // 准备插值结果
    // float3 SH0 = 0;
    // float3 SH1Lum = 0;
    Light light = GetMainLight();

    int index = _IVGIIndexGrid[baseCoord.x * _GridDim * _GridDim + baseCoord.y * _GridDim + baseCoord.z];
    // SH0   = _IVGIDataBuffer_L0[index] ;
    // SH1Lum = _IVGIDataBuffer_Luminance[index];
    //
    // float SH0Lum = max(SH0.x, max(SH0.y, SH0.z));
    // float3 SH1Lum;
    // SH1Lum.xyz = (L1.xyz * 2.0 - 1);

    float4 shAr;
    float4 shAg;
    float4 shAb;

    // if (SH0Lum < 0.05)
    // {
    //     shAr.xyz = float3(0, 0, 0);
    //     shAr.w = SH0.x;
    //     shAg.xyz = float3(0, 0, 0);
    //     shAg.w = SH0.y;
    //     shAb.xyz = float3(0, 0, 0);
    //     shAb.w = SH0.z;
    // }
    // else
    // {
    //     float3 SH1ColorX;
    //     SH1ColorX.xyz = (SH1Lum.x / SH0Lum) * SH0.xyz;
    //     float3 SH1ColorY;
    //     SH1ColorY.xyz = (SH1Lum.y / SH0Lum) * SH0.xyz;
    //     float3 SH1ColorZ;
    //     SH1ColorZ.xyz = (SH1Lum.z / SH0Lum) * SH0.xyz;
    //
    //     shAr.xyz = float3(SH1ColorX.x, SH1ColorY.x, SH1ColorZ.x);
    //     shAr.w = SH0.x;
    //     shAg.xyz = float3(SH1ColorX.y, SH1ColorY.y, SH1ColorZ.y);
    //     shAg.w = SH0.y;
    //     shAb.xyz = float3(SH1ColorX.z, SH1ColorY.z, SH1ColorZ.z);
    //     shAb.w = SH0.z;
    // }
    // shAr = float4(SH1Lum,SH0.r);
    // shAr = float4(SH1Lum,SH0.g);
    // shAr = float4(SH1Lum,SH0.b);
    // half3 L0L1Term = SHEvalLinearL0L1(normalWS, shAr, shAg, shAb);
    // return L0L1Term;
    // float ndl = saturate(dot(normalize(normalWS), normalize(SH1Lum)));
    // return SH0 + SH0 * ndl; // L0 + L1（灰度方向）

    float3 L0; //  = _IVGIDataBuffer_L0[index] ;
    float3 L1dir; // = _IVGIDataBuffer_Luminance[index];

    // 遍历 8 个邻居 probe 点
    for (int x = 0; x <= 1; ++x)
        for (int y = 0; y <= 1; ++y)
            for (int z = 0; z <= 1; ++z)
            {
                int3 offset = int3(x, y, z);
                int3 probeCoord = baseCoord + offset;
                probeCoord = clamp(probeCoord, int3(0, 0, 0), int3(_GridDim, _GridDim, _GridDim) - 1);

                int index = _IVGIIndexGrid[probeCoord.x * _GridDim * _GridDim + probeCoord.y * _GridDim + probeCoord.z];

                float weight =
                    (x == 0 ? (1.0 - voxelFrac.x) : voxelFrac.x) *
                    (y == 0 ? (1.0 - voxelFrac.y) : voxelFrac.y) *
                    (z == 0 ? (1.0 - voxelFrac.z) : voxelFrac.z);

                L0 += _IVGIDataBuffer_L0[index] * weight;
                L1dir += _IVGIDataBuffer_Luminance[index] * weight;
            }


    float ndl = saturate(dot(normalize(normalWS), normalize(L1dir)));
    return L0 + L0 * ndl; // L0 + L1（灰度方向）
}

float3 SampleIVGI_2(float3 positionWS, float3 normalWS, int dataIndex)
{
    float3 localPos = (positionWS - _GridOrigin) / _VoxelSize;
    float3 voxelF = clamp(localPos, 0.0, _GridDim - 1.001); // 防止越界
    int3 baseCoord = (int3)floor(voxelF);
    float3 voxelFrac = frac(voxelF);

    // 准备插值结果

    Light light = GetMainLight();

    int index = _IVGIIndexGrid[baseCoord.x * _GridDim * _GridDim + baseCoord.y * _GridDim + baseCoord.z];
    float3 SH0 = _IVGIDataBuffer_L0[index];
    float3 SH1 = _IVGIDataBuffer_Luminance[index];

    // float3 sh0 ;
    // float3 L1Lum ;
    //UnpackBouncedSkyVis_L0L1RGB_ToEncodedLum(SH0, SH1Lum, sh0, L1Lum);

    //FTwoBandSHVectorRGBFloat sh;
    //DecodeLumBouncedSkyVis_L0L1RGB(sh0, L1Lum, sh);
    float SH0Lum = max(SH0.x, max(SH0.y, SH0.z));
    float3 SH1Lum = (SH1.xyz * 2.0 - 1);
    // SH1Lum.xyz = (SH1.xyz * 2.0 - 1);

    float4 shAr;
    float4 shAg;
    float4 shAb;

    // if (SH0Lum < 0.05)
    // {
    //     shAr.xyz = float3(0, 0, 0);
    //     shAr.w = SH0.x;
    //     shAg.xyz = float3(0, 0, 0);
    //     shAg.w = SH0.y;
    //     shAb.xyz = float3(0, 0, 0);
    //     shAb.w = SH0.z;
    // }
    // else
    {
        float3 SH1ColorX = (SH1Lum.x / SH0Lum) * SH0.xyz;
        // SH1ColorX.xyz = (SH1Lum.x / SH0Lum) * SH0.xyz;
        float3 SH1ColorY = (SH1Lum.y / SH0Lum) * SH0.xyz;
        // SH1ColorY.xyz = (SH1Lum.y / SH0Lum) * SH0.xyz;
        float3 SH1ColorZ = (SH1Lum.z / SH0Lum) * SH0.xyz;
        // SH1ColorZ.xyz = (SH1Lum.z / SH0Lum) * SH0.xyz;

        shAr = float4(SH1ColorX.x, SH1ColorY.x, SH1ColorZ.x, SH0.x);
        // shAr.w = SH0.x;
        shAg = float4(SH1ColorX.y, SH1ColorY.y, SH1ColorZ.y, SH0.y);
        // shAg.w = SH0.y;
        shAb = float4(SH1ColorX.z, SH1ColorY.z, SH1ColorZ.z, SH0.z);
        // shAb.w = SH0.z;
    }

    //float3 r = SHEvaluate_L0L1RGB(normalize(normalWS), sh);
    half3 L0L1Term = SHEvalLinearL0L1(normalize(normalWS), shAr, shAg, shAb);
    return L0L1Term;
}

void UnpackSHL0L1(float3 positionWS, out float3 SHL0, out float3 SHL1)
{
    float3 localPos = (positionWS - _GridOrigin) / _VoxelSize;
    float3 voxelF = clamp(localPos, 0.0, _GridDim - 1.001); // 防止越界
    int3 coord = (int3)floor(voxelF);
    int index = _IVGIIndexGrid[coord.x * _GridDim * _GridDim + coord.y * _GridDim + coord.z];
    SHL0 = _IVGIDataBuffer_L0[index];
    SHL1 = _IVGIDataBuffer_Luminance[index];
}

void ReconstructSHCoefficient(float3 SHL0, float3 SHL1, out float4 shAr, out float4 shAg, out float4 shAb)
{
    //float L0Lum = max(SHL0.x, max(SHL0.y, SHL0.z));
    float L0Lum = max(0.001, max(SHL0.r, max(SHL0.g, SHL0.b)));

    float3 L1Lum = (SHL1.xyz * 2.0 - 1);

    float3 SH1ColorX = (L1Lum.x / L0Lum) * SHL0.xyz;
    float3 SH1ColorY = (L1Lum.y / L0Lum) * SHL0.xyz;
    float3 SH1ColorZ = (L1Lum.z / L0Lum) * SHL0.xyz;

    // SH1ColorX.x = max(SH1ColorX.x,0);
    // SH1ColorX.y = max(SH1ColorX.y,0);
    // SH1ColorX.z = max(SH1ColorX.z,0);
    //
    // SH1ColorY.x = max(SH1ColorY.x,0);
    // SH1ColorY.y = max(SH1ColorY.y,0);
    // SH1ColorY.z = max(SH1ColorY.z,0);
    //
    // SH1ColorZ.x = max(SH1ColorZ.x,0);
    // SH1ColorZ.y = max(SH1ColorZ.y,0);
    // SH1ColorZ.z = max(SH1ColorZ.z,0);
    
    shAr = float4(SH1ColorX.x, SH1ColorY.x, SH1ColorZ.x, SHL0.x);
    shAg = float4(SH1ColorX.y, SH1ColorY.y, SH1ColorZ.y, SHL0.y);
    shAb = float4(SH1ColorX.z, SH1ColorY.z, SH1ColorZ.z, SHL0.z);
}

float3 SampleIVGI(float3 positionWS, float3 normalWS)
{
    float3 SHL0, SHL1;
    UnpackSHL0L1(positionWS, SHL0, SHL1);
    
    float4 shAr, shAg, shAb;
    ReconstructSHCoefficient(SHL0, SHL1,shAr, shAg, shAb);

    float3 indirect = SHEvalLinearL0L1(normalize(normalWS), shAr, shAg, shAb);
    return indirect;
}

//TEX
TEXTURE3D(_IVGIDataBuffer_L0_Tex);
SAMPLER(sampler_IVGIDataBuffer_L0_Tex);
TEXTURE3D(_IVGIDataBuffer_Luminance_Tex);
SAMPLER(sampler_IVGIDataBuffer_Luminance_Tex);

void UnpackSHL0L1_Tex(float3 positionWS, float3 normalWS, out float3 SHL0, out float3 SHL1)
{
    float3 localPos = (positionWS - _GridOrigin) / _VoxelSize + normalize(normalWS);
    float3 voxelF = clamp(localPos, 0.0, _GridDim - 1.001); // 防止越界

    //float3 uvw = frac(voxelF / _GridDim );
    float3 uvw = voxelF / (_GridDim - 1.0);

    SHL0 = SAMPLE_TEXTURE3D_LOD(_IVGIDataBuffer_L0_Tex, sampler_IVGIDataBuffer_L0_Tex, uvw, 0).rgba;
    SHL1 = SAMPLE_TEXTURE3D_LOD(_IVGIDataBuffer_Luminance_Tex, sampler_IVGIDataBuffer_Luminance_Tex, uvw, 0).rgba;
}

real3 _SHEvalLinearL0L1(real3 N, real4 shAr, real4 shAg, real4 shAb)
{
    real4 vA = real4(N, 1.0);
    vA = EvalSHTwoBand(vA);
    real3 x1;
    // Linear (L1) + constant (L0) polynomial terms
    x1.r = dot(shAr, vA);
    x1.g = dot(shAg, vA);
    x1.b = dot(shAb, vA);

    return x1;
}

float3 SampleIVGI_Tex(float3 positionWS, float3 normalWS)
{
    float3 SHL0, SHL1;
    UnpackSHL0L1_Tex(positionWS,normalWS, SHL0, SHL1);
    
    float4 shAr, shAg, shAb;
    ReconstructSHCoefficient(SHL0, SHL1,shAr, shAg, shAb);

    float3 indirect = SHEvalLinearL0L1(normalize(normalWS), shAr, shAg, shAb);
    return SHL0 ;
}
#endif
